package net.sea.commons.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;

/**
 * 
 * 修改Jar包中的文件
 *
 * @author cuitingting
 */
public class JarEditorUtil {
	/**
	 * 修改jar包里属性文件
	 * 
	 * @param file
	 *            jar包路径
	 * @param entryName
	 *            修改属性文件名
	 * @param map
	 *            修改内容（键值对）
	 */
	@Deprecated
	public static void editJar(String file, String entryName,
			Map<String, String> map) {
		JarOutputStream out = null;
		try {
			JarFile jf = new JarFile(file);
			TreeMap<String, Properties> tm = new TreeMap<String, Properties>();
			Enumeration<JarEntry> es = jf.entries();
			while (es.hasMoreElements()) {
				JarEntry je = es.nextElement();
				Properties props = new Properties();
				props.load(jf.getInputStream(je));
				tm.put(je.getName(), props);
			}
			out = new JarOutputStream(new FileOutputStream(file));

			Set<String> keySet = tm.keySet();
			for (String key : keySet) {
				JarEntry jeNew = new JarEntry(key);
				out.putNextEntry(jeNew);
				Properties props = tm.get(key);
				if (key.contains(entryName)) {
					props = updFile(props, map);
				}
				props.store(out, "");
			}
			// Set<Entry<String, Properties>> set = tm.entrySet();
			// Iterator it = set.iterator();
			// while (it.hasNext()) {
			// Map.Entry me = (Map.Entry) it.next();
			// String name = (String) me.getKey();
			// JarEntry jeNew = new JarEntry(name);
			// out.putNextEntry(jeNew);
			// Properties props = (Properties) me.getValue();
			// if (name.contains(entryName)) {
			// props = updFile(props, map);
			// }
			// props.store(out, "");
			// }
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (out != null) {
				try {
					out.finish();
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
					out = null;
				}
			}
		}
	}

	/**
	 * 修改jar中的属性配置文件
	 * 
	 * @author 华成伍
	 * 
	 * @param original
	 *            源jar文件
	 * @param configPath
	 *            配置文件地址
	 * @param cfgs
	 *            要修改的配置信息
	 * @throws FileNotFoundException
	 */
	public static void write2JarFile(File original, String configPath,
			Map<String, String> cfgs) throws FileNotFoundException {
		if (original == null) {
			return;
		}
		if (!original.exists()) {
			throw new FileNotFoundException("未找到指定jar包");
		}
		String originalPath = original.getAbsolutePath();

		/** 创建一个临时文件来做暂存，待一切操作完毕之后会将该文件重命名为原文件的名称(原文件会被删除掉) */
		String tempPath = originalPath.substring(0, originalPath.length() - 4)
				+ "_temp.jar";
		JarFile originalJar = null;
		JarOutputStream jos = null;
		try {
			// 遍历jar中的所有文件
			originalJar = new JarFile(originalPath);
			List<JarEntry> jarFiles = new LinkedList<JarEntry>();
			for (Enumeration<JarEntry> entrys = originalJar.entries(); entrys
					.hasMoreElements();) {
				JarEntry jarEntry = entrys.nextElement();
				jarFiles.add(jarEntry);
			}

			File handled = new File(tempPath);
			FileOutputStream fos = new FileOutputStream(handled);
			jos = new JarOutputStream(fos);

			/**
			 * 将源文件中的内容复制过来 可以利用循环将一个文件夹中的文件都写入jar包中 其实很简单
			 */
			for (JarEntry je : jarFiles) {
				// jar 中的每一个文件夹 每一个文件 都是一个 jarEntry
				JarEntry newEntry = new JarEntry(je.getName());

				// newEntry.setComment(je.getComment());
				// newEntry.setCompressedSize(je.getCompressedSize());
				// newEntry.setCrc(je.getCrc());
				// newEntry.setExtra(je.getExtra());
				// newEntry.setMethod(je.getMethod());
				// newEntry.setTime(je.getTime());
				// System.out.println(je.getAttributes());
				/** 这句代码有问题，会导致将jar包重命名为zip包之后无法解压缩 */
				// newEntry.setSize(je.getSize());

				// 表示将该entry写入jar文件中 也就是创建该文件夹和文件
				jos.putNextEntry(newEntry);

				/** 如果当前已经处理到属性文件了，写入到该属性文件 */
				InputStream is = originalJar.getInputStream(je);
				if (je.getName().equals(configPath)) {
					Properties props = new Properties();
					props.load(is);
					props = updFile(props, cfgs);
					props.store(jos, "");
					is.close();
					continue;
				}

				byte[] bytes = inputStream2byteArray(is);
				is.close();

				// 写入文件中
				jos.write(bytes);
			}
			jos.close();
			fos.close();
			// 关闭jar
			originalJar.close();

			/** 删除原始文件，将新生成的文件重命名为原始文件的名称 */
			original.delete();
			// original.renameTo(new File(originalPath + ".bak"));
			handled.renameTo(new File(originalPath));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * InputStream 转 byte[]
	 * 
	 * @param is
	 * @return
	 */
	private static byte[] inputStream2byteArray(InputStream is) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		int i;
		try {
			while ((i = is.read()) != -1) {
				baos.write(i);
			}
			baos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		byte[] bytes = baos.toByteArray();
		return bytes;
	}

	/**
	 * 替换属性文件中内容
	 * 
	 * @param props
	 *            属性文件
	 * @param map
	 *            修改内容（键值对）
	 * @return
	 */
	private static Properties updFile(Properties props, Map<String, String> map) {
		Set<String> key = map.keySet();
		Iterator<String> i = key.iterator();
		while (i.hasNext()) {
			String s = i.next();
			if (props.getProperty(s) != null) {
				props.setProperty(s, map.get(s));
			}
		}
		return props;
	}

}
